package com.yanqu.road.server.gameplayer.module.activity.fellingtrees;

import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.args.FellingTreesLevelArgs;
import com.yanqu.road.entity.activity.fellingtrees.*;
import com.yanqu.road.entity.activity.fellingtrees.config.FellingTreesConfig;
import com.yanqu.road.entity.activity.fellingtrees.config.FellingTreesElixirConfig;
import com.yanqu.road.entity.activity.fellingtrees.config.FellingTreesLevelConfig;
import com.yanqu.road.entity.activity.fellingtrees.config.FellingTreesMultiConfig;
import com.yanqu.road.entity.activity.fellingtrees.config.FellingTreesWeaponsConfig;
import com.yanqu.road.entity.activity.fellingtrees.helper.SpecialEquipAddResultHelper;
import com.yanqu.road.entity.config.goods.GoodsInfo;
import com.yanqu.road.entity.enums.*;
import com.yanqu.road.entity.log.LogFellingTreesPlay;
import com.yanqu.road.entity.log.LogFellingTreesEnergy;
import com.yanqu.road.entity.log.LogFellingTreesEquip;
import com.yanqu.road.entity.log.LogFellingTreesItem;
import com.yanqu.road.entity.log.LogFellingTreesUnlockPos;
import com.yanqu.road.logic.bussiness.activity.FellingTreesBusiness;
import com.yanqu.road.logic.helper.CalcPowerResult;
import com.yanqu.road.logic.helper.PowerHelper;
import com.yanqu.road.pb.activity.FellingTreesProto;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.fellingtrees.FellingTreesEffectLogic;
import com.yanqu.road.server.manger.activity.fellingtrees.FellingTreesMgr;
import com.yanqu.road.server.manger.config.GoodsMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.pb.FellingTreesPb;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class FellingTreesModule extends GeneralModule {

    private FellingTreesUserData fellingTreesUserData;

    public FellingTreesModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {
        ActivityInfo activityInfo = FellingTreesMgr.getActivityInfo();
        if (ActivityMgr.activityInShowTime(activityInfo)) {
            fellingTreesUserData = FellingTreesBusiness.getFellingTreesUserData(activityInfo.getActivityId(), getUserId());
            if (fellingTreesUserData == null) {
                initUserData();
            }
        }
        return true;
    }

    @Override
    public boolean afterLoadData() {
        return true;
    }

    @Override
    public boolean saveData() {
        if (fellingTreesUserData != null) {
            if (fellingTreesUserData.isInsertOption()) {
                FellingTreesBusiness.addFellingTreesUserData(fellingTreesUserData);
            } else if (fellingTreesUserData.isUpdateOption()) {
                FellingTreesBusiness.updateFellingTreesUserData(fellingTreesUserData);
            }
        }
        return true;
    }

    @Override
    public void afterLogin() {
        refreshData();
        if (fellingTreesUserData != null && FellingTreesMgr.getFellingTreesConfig() != null) {
            finishDaoqiGuide();
            finishRabbitGuide();
            finishSpecialEquipGuide();
        }

    }

    public void refreshData() {
        initUserData();
        syncConfig();
        syncUserData();
    }

    public synchronized FellingTreesUserData getUserData() {
        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();
        if (fellingTreesUserData != null && config != null) {

            int logEnergy = fellingTreesUserData.getEnergy();

            // 体力
            CalcPowerResult result = PowerHelper.calcPower(
                    fellingTreesUserData.getRecoveryTime() / 1000,
                    config.getEnergyRecTime() / 1000,
                    config.getEnergyRecCount(),
                    config.getMaxEnergy(),
                    fellingTreesUserData.getEnergy());
            fellingTreesUserData.setEnergy(result.getCurPower());
            fellingTreesUserData.setRecoveryTime(result.getLastRecoverTime() * 1000L);


            // 日志
            if (fellingTreesUserData.getEnergy() != logEnergy) {
                AutoLogMgr.add(new LogFellingTreesEnergy(
                        config.getActivityInfo().getActivityId(),
                        getUserId(),
                        LogFellingTreesEnergy.TYPE_CUT_ENERGY,
                        LogFellingTreesEnergy.SON_TYPE_AUTO_REC,
                        fellingTreesUserData.getEnergy() - logEnergy,
                        fellingTreesUserData.getEnergy()
                ));
            }
        }
        return fellingTreesUserData;
    }

    private synchronized void initUserData() {
        // 没解锁
        if (!SystemOpenMgr.systemOpen(player, eSystemId.FellingTreesActivity.getValue())) {
            return;
        }
        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();
        // 没活动
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }
        // 已有数据
        if (fellingTreesUserData != null && fellingTreesUserData.getActivityId() == config.getActivityInfo().getActivityId()) {
            return;
        }

        long now = System.currentTimeMillis();

        // 初始化装备栏
        int[][] posConfig = config.getPosConfig();
        long[] posArr = new long[posConfig.length * posConfig[0].length];
        int index = 0;
        for (int y = posConfig.length - 1; y >= 0; y--) {
            for (int x = 0; x < posConfig[y].length; x++) {
                posArr[index++] = posConfig[y][x];
            }
        }

        // 获取等级1的树血量
        FellingTreesLevelConfig levelConfig = config.getLevelConfigMap().get(1);
        BigInteger hp = levelConfig.getHp();

        // 默认设置
        FellingTreesSetting setting = new FellingTreesSetting();
        setting.setAutoEquip(false);
        setting.setAutoRecycle(false);

        FellingTreesUserData userData = new FellingTreesUserData();
        userData.setActivityId(config.getActivityInfo().getActivityId());
        userData.setUserId(getUserId());
        userData.setGold(BigInteger.ZERO);
        userData.setAttack(config.getInitAttack());
        userData.setTopLevel(0);
        userData.setEquipPosArr(posArr);
        userData.setEquipMap(new ConcurrentHashMap<>());
        userData.setItems(new Property());
        userData.setMaxUid(0);
        userData.setBuffMap(new ConcurrentHashMap<>());
        userData.setEnergy(config.getMaxEnergy());
        userData.setRecoveryTime(now);
        userData.setRabbitRecoveryTime(now);
        userData.setRabbitGuide(false);
        userData.setLastLevel(1);
        userData.setLastHp(hp);
        userData.setSetting(setting);
        userData.setSpecialEquipGuide(false);
        userData.setDaoqiGuide(false);
        userData.setInsertOption();
        fellingTreesUserData = userData;
    }

    private void syncConfig() {
        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();
        if (config != null) {
            FellingTreesProto.FellingTreesSyncConfigRespMsg.Builder builder = FellingTreesPb.parseFellingTreesSyncConfigRespMsg(config);
            player.sendPacket(ClientProtocol.U_FELLING_TREES_SYNC_CONFIG, builder);
        }
    }

    private void syncUserData() {
        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();
        FellingTreesUserData userData = getUserData();
        if (config != null && userData != null) {
            FellingTreesProto.FellingTreesSyncDataRespMsg.Builder builder = FellingTreesProto.FellingTreesSyncDataRespMsg.newBuilder();
            builder.setUserData(FellingTreesPb.parseFellingTreesUserDataMsg(userData));
            player.sendPacket(ClientProtocol.U_FELLING_TREES_SYNC_DATA, builder);
        }
    }

    private synchronized long getNextUid(FellingTreesUserData userData) {
        userData.setMaxUid(userData.getMaxUid() + 1);
        return userData.getMaxUid();
    }

    private boolean hasThisEquip(Map<Long, FellingTreesEquip> allEquipMap, int equipId) {
        return allEquipMap.values().stream().anyMatch(item -> item.getEquipId() == equipId);
    }

    /**
     * 可装备的数量
     *
     * @param config
     * @param userData
     * @return
     */
    private boolean isWearEquipLimit(FellingTreesConfig config, FellingTreesUserData userData, int equipType) {
        long[] equipPosArr = userData.getEquipPosArr();
        Map<Long, FellingTreesEquip> equipMap = userData.getEquipMap();

        Map<Integer, Integer> map;
        if (equipType == eFellingTreesEquipType.SpecialEquip.getValue()) {
            // 灵宝
            map = config.getPosSpecialEquipMap();
        } else if (equipType == eFellingTreesEquipType.DaoQi.getValue()) {
            // 道器
            map = config.getPosDaoQiMap();
        } else {
            // 其他类型暂不限制
            return true;
        }
        // 拥有的格子数
        int posCount = (int) (Arrays.stream(equipPosArr).filter(item -> item >= 0).count());
        // 可装备数量
        int canWearCount = 0;
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            if (posCount >= entry.getKey()) {
                canWearCount = Math.max(entry.getValue(), canWearCount);
            }
        }
        // 已装备灵宝数量
        int hadWearCount = 0;
        Map<Integer, FellingTreesWeaponsConfig> weaponsConfigMap = config.getWeaponsConfigMap();
        for (long equipId : equipPosArr) {
            if (equipId > 0) {
                FellingTreesEquip tmpEquip = equipMap.get(equipId);
                FellingTreesWeaponsConfig tmpConfig = weaponsConfigMap.get(tmpEquip.getEquipId());
                if (tmpConfig.getType() == equipType) {
                    hadWearCount++;
                }
            }
        }
        // 是否到上限制
        return hadWearCount >= canWearCount;
    }

    private int getUnlockPosCount(FellingTreesConfig config, long[] equipPosArr) {
        // 免费格子数
        int freeCount = 0;
        for (int[] arr : config.getPosConfig()) {
            for (int intValue : arr) {
                if (intValue != -1) {
                    freeCount++;
                }
            }
        }
        // 当前格子数
        int nowCount = (int) (Arrays.stream(equipPosArr).filter(item -> item >= 0).count());
        // 解锁格子数
        return nowCount - freeCount;
    }

    private int useEnergyItem(FellingTreesConfig config, FellingTreesUserData userData, int itemId, int count) {
        // 拿恢复数量
        GoodsInfo goodsInfo = GoodsMgr.getGoodsById(itemId);
        if (goodsInfo == null) {
            return GameErrorCode.E_GOODS_NO_EXIST;
        }
        int recoveryNum = goodsInfo.getParamList().get(0).intValue();

        // 扣道具
        Property cost = PropertyHelper.parseStringToProperty(itemId + "=" + count);
        if (!player.getModule(CurrencyModule.class).removeCurrency(cost, eLogMoneyType.FellingTreesActivity, eLogMoneyType.FellingTreesActivityUseEnergyItem)) {
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }

        int logEnergy = userData.getEnergy();

        // 恢复体力
        userData.setEnergy(userData.getEnergy() + recoveryNum * count);
        if (userData.getEnergy() >= config.getMaxEnergy()) {
            userData.setRecoveryTime(System.currentTimeMillis());
        }

        // 日志
        AutoLogMgr.add(new LogFellingTreesEnergy(
                config.getActivityInfo().getActivityId(),
                getUserId(),
                LogFellingTreesEnergy.TYPE_CUT_ENERGY,
                LogFellingTreesEnergy.SON_TYPE_ITEM_REC,
                fellingTreesUserData.getEnergy() - logEnergy,
                fellingTreesUserData.getEnergy()
        ));

        return 0;
    }

    private int useBuffItem(FellingTreesConfig config, FellingTreesUserData userData, int itemId, int count) {
        FellingTreesElixirConfig elixirConfig = config.getElixirConfigMap().get(itemId);
        if (elixirConfig == null) {
            return GameErrorCode.E_GOODS_NO_EXIST;
        }

        int buffId = itemId;
        int addTimes = elixirConfig.getTimes() * count;

        // 扣道具
        Property cost = new Property();
        cost.addProperty(itemId, BigInteger.valueOf(count));
        if (!removeItem(config, userData, cost, eFellingTreesWay.UseBuffItem.getValue())) {
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }

        // 加buff次数
        Map<Integer, Integer> buffMap = userData.getBuffMap();
        int oldTimes = buffMap.getOrDefault(buffId, 0);
        buffMap.put(buffId, oldTimes + addTimes);

        return 0;
    }

    private void calcAttack(FellingTreesConfig config, FellingTreesUserData userData) {

        BigInteger oldValue = userData.getAttack();

        Map<Integer, FellingTreesWeaponsConfig> weaponsConfigMap = config.getWeaponsConfigMap();
        Map<Integer, FellingTreesLevelConfig> levelConfigMap = config.getLevelConfigMap();
        Map<Long, FellingTreesEquip> equipMap = userData.getEquipMap();
        int height = config.getPosConfig().length; // 装备栏高度
        int width = config.getPosConfig()[0].length; // 装备栏宽度
        long[] equipPosArr = userData.getEquipPosArr();

        // 统计
        Map<Integer, BigInteger> attackMap = new HashMap<>(); // 基础攻击力 + 其他法宝固定值
        Map<Integer, Long> additionMap = new HashMap<>(); // 法宝加成千分比

        // 遍历装备
        for (int index = 0; index < equipPosArr.length; index++) {
            long equipUid = equipPosArr[index];
            if (equipUid <= 0) {
                continue;
            }

            FellingTreesEquip equip = equipMap.get(equipUid);
            FellingTreesWeaponsConfig weaponsConfig = weaponsConfigMap.get(equip.getEquipId());
            FellingTreesLevelConfig levelConfig = levelConfigMap.get(equip.getLv());

            // 本身攻击力
            int baseAttackPercent = weaponsConfig.getBaseAttack();
            BigInteger baseAttack = levelConfig.getWeaponAtt();
            BigInteger attack = new BigDecimal(baseAttack.multiply(BigInteger.valueOf(baseAttackPercent)))
                    .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).toBigInteger();
            attackMap.put(index, attackMap.getOrDefault(index, BigInteger.ZERO).add(attack));

            // 装备效果生效
            List<Integer> effectIndexList = FellingTreesEffectLogic.getEffectIndexList(weaponsConfig.getEffectType(), weaponsConfig.getEffectDirection(), index, height, width);
            if (weaponsConfig.getType() == eFellingTreesEquipType.Normal.getValue()) {
                // 法宝固定值加成
                int effectAttackAddition = weaponsConfig.getEffectAttack();
                BigInteger addition = new BigDecimal(baseAttack.multiply(BigInteger.valueOf(effectAttackAddition)))
                        .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).toBigInteger();
                for (Integer tmpIndex : effectIndexList) {
                    attackMap.put(tmpIndex, attackMap.getOrDefault(tmpIndex, BigInteger.ZERO).add(addition));
                }
            } else if (weaponsConfig.getType() == eFellingTreesEquipType.SpecialEquip.getValue()) {
                // 灵宝千分比
                int effectAttackAddition = BigDecimal.valueOf(weaponsConfig.getEffectAttack())
                        .multiply(BigDecimal.valueOf(1000 + (equip.getLv() - equip.getBaseLv()) * config.getSpecialEquipUpgradeAddition()))
                        .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP)
                        .intValue();
                for (Integer tmpIndex : effectIndexList) {
                    additionMap.put(tmpIndex, additionMap.getOrDefault(tmpIndex, 0L) + effectAttackAddition);
                }
            } else if (weaponsConfig.getType() == eFellingTreesEquipType.DaoQi.getValue()) {
                // 道器这边不处理
                continue;
            }

        }

        // 计算灵宝加成，结果覆盖attackMap
        for (Map.Entry<Integer, Long> entry : additionMap.entrySet()) {
            int index = entry.getKey();
            long addition = entry.getValue();
            if (attackMap.containsKey(index)) {
                BigInteger attack = attackMap.get(index);
                BigInteger newAttack = new BigDecimal(attack.multiply(BigInteger.valueOf(1000 + addition)))
                        .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).toBigInteger();
                attackMap.put(index, newAttack);
            }
        }

        // 计算道器加成，结果覆盖attackMap
        for (int index = 0; index < equipPosArr.length; index++) {
            long equipUid = equipPosArr[index];
            if (equipUid <= 0) {
                continue;
            }

            FellingTreesEquip equip = equipMap.get(equipUid);
            FellingTreesWeaponsConfig weaponsConfig = weaponsConfigMap.get(equip.getEquipId());
            // 只处理道器
            if (weaponsConfig.getType() != eFellingTreesEquipType.DaoQi.getValue()) {
                continue;
            }
            // 装备效果生效
            List<Integer> effectIndexList = FellingTreesEffectLogic.getEffectIndexList(weaponsConfig.getEffectType(), weaponsConfig.getEffectDirection(), index, height, width);

            // 计算当前道器加成(复制千分比)
            int addition = weaponsConfig.getEffectAttack();
            for (FellingTreesEquipParam equipParam : equip.getParamList()) {
                if (equipParam.getType() == eFellingTreesEquipParamType.DaoQi.getValue()) {
                    addition += equipParam.getValue();
                }
            }
            // 复制法力
            BigInteger totalEffectAttack = BigInteger.ZERO;
            for (Integer tmpIndex : effectIndexList) {
                if (attackMap.containsKey(tmpIndex)) {
                    FellingTreesEquip tmpEquip = getEquip(tmpIndex);
                    if (tmpEquip == null) {
                        continue;
                    }
                    FellingTreesWeaponsConfig tmpWeaponsConfig = weaponsConfigMap.get(tmpEquip.getEquipId());
                    // 只复制装备
                    if (tmpWeaponsConfig.getType() != eFellingTreesEquipType.Normal.getValue()) {
                        continue;
                    }
                    totalEffectAttack = totalEffectAttack.add(attackMap.get(tmpIndex));
                }
            }
            BigInteger totalAttack = new BigDecimal(totalEffectAttack.multiply(BigInteger.valueOf(addition))).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).toBigInteger();
            attackMap.put(index, totalAttack);
        }

        // 最终攻击力，需要那个位置有装备
        BigInteger sum = config.getInitAttack();
        for (Map.Entry<Integer, BigInteger> entry : attackMap.entrySet()) {
            long uid = equipPosArr[entry.getKey()];
            if (uid > 0) {
                FellingTreesEquip equip = equipMap.get(uid);
                FellingTreesWeaponsConfig weaponsConfig = weaponsConfigMap.get(equip.getEquipId());
                if (weaponsConfig.getType() == eFellingTreesEquipType.Normal.getValue() ||
                        weaponsConfig.getType() == eFellingTreesEquipType.DaoQi.getValue()) {
                    sum = sum.add(entry.getValue());
                }
            }
        }

        // 设置
        userData.setAttack(sum);

        // 更新榜单
        if (userData.getAttack().compareTo(oldValue) > 0) {
            player.notifyListener(eGamePlayerEventType.FellingTreesLevelRank.getValue(), FellingTreesLevelArgs.create(config, userData));
            player.notifyListener(eGamePlayerEventType.FellingTreesAttackCondition.getValue(), userData.getAttack());
        }
    }

    private FellingTreesEquip getEquip(int index) {
        FellingTreesUserData userData = getUserData();
        long equipUid = userData.getEquipPosArr()[index];
        if (equipUid <= 0) {
            return null;
        }
        return userData.getEquipMap().get(equipUid);
    }


    private boolean removeEnergy(FellingTreesConfig config, FellingTreesUserData userData, int count) {
        if (userData.getEnergy() < count) {
            return false;
        }

        boolean beforeMax = userData.getEnergy() >= config.getMaxEnergy();

        // 改体力
        userData.setEnergy(userData.getEnergy() - count);

        if (beforeMax && userData.getEnergy() < config.getMaxEnergy()) {
            userData.setRecoveryTime(System.currentTimeMillis());
        }
        return true;
    }

    private List<Long> getBuffAddition(FellingTreesConfig config, eFellingTreesBuffType type, Map<Integer, Integer> buffMap) {
        Integer times = buffMap.getOrDefault(type.getValue(), 0);
        if (times <= 0) {
            return null;
        }

        FellingTreesElixirConfig elixirConfig = config.getElixirConfigMap().get(type.getValue());
        return elixirConfig.getParamList();
    }

    private boolean bagIsFull(FellingTreesConfig config, FellingTreesUserData userData) {
        // 身上穿的
        Set<Long> equipSet = new HashSet<>();
        for (long uid : userData.getEquipPosArr()) {
            if (uid > 0) {
                equipSet.add(uid);
            }
        }
        // 看哪些占用格子
        int count = 0;
        Map<Integer, FellingTreesWeaponsConfig> weaponsConfigMap = config.getWeaponsConfigMap();
        for (FellingTreesEquip equip : userData.getEquipMap().values()) {
            if (!equipSet.contains(equip.getUid())) { // 没穿戴
                if (weaponsConfigMap.get(equip.getEquipId()).getType() == eFellingTreesEquipType.Normal.getValue()) { // 是法宝
                    count++;
                    if (count >= config.getBagSize()) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    private BigInteger getUpgradeGold(FellingTreesConfig config, int baseLv, int lv) {
        List<Long> costList = config.getEquipUpgradeCost();
        long costPercent = costList.get(Math.min(costList.size() - 1, lv - baseLv));
        FellingTreesLevelConfig levelConfig = config.getLevelConfigMap().get(lv + 1);
        BigInteger cost = new BigDecimal(BigInteger.valueOf(costPercent).multiply(levelConfig.getStrengthGold()))
                .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).toBigInteger();
        return cost;
    }


    /**
     * 获取已拥有的道器
     *
     * @param config
     * @param userData
     */
    private Set<Integer> getAllDaoQiEquipId(FellingTreesConfig config, FellingTreesUserData userData) {
        Set<Integer> idSet = new HashSet<>();
        Map<Integer, FellingTreesWeaponsConfig> weaponsConfigMap = config.getWeaponsConfigMap();
        for (FellingTreesEquip equip : userData.getEquipMap().values()) {
            FellingTreesWeaponsConfig weaponsConfig = weaponsConfigMap.get(equip.getEquipId());
            if (weaponsConfig.getType() == eFellingTreesEquipType.DaoQi.getValue()) {
                idSet.add(equip.getEquipId());
            }
        }
        return idSet;
    }

    /**
     * 身上有没有道器
     *
     * @param config
     * @param userData
     * @return
     */
    private boolean haveDaoqi(FellingTreesConfig config, FellingTreesUserData userData) {
        Map<Integer, FellingTreesWeaponsConfig> weaponsConfigMap = config.getWeaponsConfigMap();
        for (FellingTreesEquip equip : userData.getEquipMap().values()) {
            FellingTreesWeaponsConfig weaponsConfig = weaponsConfigMap.get(equip.getEquipId());
            if (weaponsConfig.getType() == eFellingTreesEquipType.DaoQi.getValue()) {
                return true;
            }
        }
        return false;
    }


    // ==========================================

    /**
     * 进入界面获取数据
     */
    public int getData() {
        FellingTreesUserData userData = getUserData();

        FellingTreesProto.FellingTreesGetDataRespMsg.Builder builder = FellingTreesProto.FellingTreesGetDataRespMsg.newBuilder();
        builder.setRet(0);
        builder.setUserData(FellingTreesPb.parseFellingTreesUserDataMsg(userData));
        builder.addAllItem(FellingTreesPb.parseFellingTreesItemMsgList(userData.getItems()));
        builder.addAllEquip(FellingTreesPb.parseFellingTreesEquipMsgList(userData.getEquipMap().values()));
        builder.setSetting(FellingTreesPb.parseFellingTreesSettingMsg(userData.getSetting()));
        player.sendPacket(ClientProtocol.U_FELLING_TREES_GET_DATA, builder);
        return 0;
    }

    /**
     * 砍树
     */
    public int play(boolean skip, boolean isSkipGuide) {
        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();
        FellingTreesUserData userData = getUserData();

        // 背包满了
        if (bagIsFull(config, userData)) {
            return GameErrorCode.E_FELLING_TREES_BAG_FULL;
        }

        // 多倍
        FellingTreesMultiConfig multiConfig = config.getMultiConfigList().get(0);
        for (FellingTreesMultiConfig tmp : config.getMultiConfigList()) {
            if (userData.getTopLevel() >= tmp.getLv()) {
                multiConfig = tmp;
            } else {
                break;
            }
        }

        // 体力不足
        int costEnergy = multiConfig.getCost();
        if (userData.getEnergy() < costEnergy) {
            return GameErrorCode.E_FELLING_TREES_ENERGY_NO_ENOUGH;
        }

        int logEnergy = userData.getEnergy();

        // 计算积分奖励
        Property scoreReward = new Property();
        long scoreLong = config.getEnergyToScore() * costEnergy;
        scoreReward.addProperty(config.getScoreItemId(), BigInteger.valueOf(scoreLong));

        // 重新计算攻击力
        calcAttack(config, userData);

        // buff加成攻击力
        BigInteger attack = userData.getAttack();
        List<Long> buffAddition = getBuffAddition(config, eFellingTreesBuffType.AddAttack, userData.getBuffMap());
        if (buffAddition != null) {
            attack = new BigDecimal(attack.multiply(BigInteger.valueOf(1000 + buffAddition.get(0))))
                    .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).toBigInteger();
        }
        BigInteger perAttack = attack; // 记录下每刀伤害

        // 砍树次数
        int attackTimes = config.getAttackTimes();
        List<Long> attackTimesAddi = getBuffAddition(config, eFellingTreesBuffType.AddAttackTimes, userData.getBuffMap());
        if (attackTimesAddi != null) {
            attackTimes = BigDecimal.valueOf((1000 + attackTimesAddi.get(0)) * attackTimes)
                    .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).intValue();
        }

        attack = attack.multiply(BigInteger.valueOf(attackTimes));

        BigInteger logDamage = attack; // 日志

        Map<Integer, FellingTreesLevelConfig> levelConfigMap = config.getLevelConfigMap();
        List<FellingTreesReward> rewardList = new ArrayList<>();
        int lastLv = 1;
        BigInteger lastHp = levelConfigMap.get(1).getHp();
        // 已拥有的道器id
        Set<Integer> allDaoQiEquipId = getAllDaoQiEquipId(config, userData);

        // 砍树开始
        Random random = new Random();
        for (int lv = 1; lv <= levelConfigMap.size(); lv++) {
            FellingTreesLevelConfig levelConfig = levelConfigMap.get(lv);
            BigInteger hp = levelConfig.getHp();

            // 砍不动：结束
            if (attack.compareTo(hp) < 0) {
                lastLv = lv;
                lastHp = hp.subtract(attack);
                break;
            }

            // 扣攻击
            attack = attack.subtract(hp);

            FellingTreesReward reward = new FellingTreesReward(lv);
            for (int times = 0; times < multiConfig.getTimes(); times++) {
                // 掉落法宝
                List<FellingTreesEquip> dropEquipList = FellingTreesMgr.getDropNormalEquipList(random, userData.getTopLevel(), lv,
                        getBuffAddition(config, eFellingTreesBuffType.DropNormalEquip, userData.getBuffMap()), times == 0);
                reward.getNormalEquipList().addAll(dropEquipList);
                // 掉落药材
                int dropItem = FellingTreesMgr.getDropItem(random, lv);
                if (dropItem > 0) {
                    reward.getItems().addProperty(dropItem, BigInteger.ONE);
                }
                // 掉落灵宝
                FellingTreesMgr.getDropSpecialEquip(random, lv, getBuffAddition(config, eFellingTreesBuffType.DropSpecialEquip, userData.getBuffMap()), reward);
                // 掉落道器
                FellingTreesMgr.dropDaoQi(config, lv, allDaoQiEquipId, reward);
                // 掉落月灵石
                FellingTreesMgr.getDropMoonStone(random, lv, getBuffAddition(config, eFellingTreesBuffType.DropMoonStone, userData.getBuffMap()), reward);

                // 掉落金币
                BigInteger gold = levelConfig.getGold();
                List<Long> goldAddition = getBuffAddition(config, eFellingTreesBuffType.DropGold, userData.getBuffMap());
                if (goldAddition != null) {
                    gold = gold.multiply(BigInteger.valueOf(1000 + goldAddition.get(0))).divide(BigInteger.valueOf(1000));
                }
                reward.setGold(reward.getGold().add(gold));
            }
            rewardList.add(reward);

            // 全部砍光了
            if (lv == levelConfigMap.size()) {
                lastLv = lv;
                lastHp = BigInteger.ZERO;
                break;
            }
        }
        int cutDownLv = lastHp.compareTo(BigInteger.ZERO) == 0 ? lastLv : lastLv - 1; // 砍倒的等级

        // 熔炼的装备转化为金币
        int recycleCount = 0;
        int maxDropEquipLevel = config.getMaxDropEquipLevel();
        FellingTreesLevelConfig levelConfig = config.getLevelConfigMap().get(cutDownLv);
        List<Integer> autoSellWeaponLevelList = levelConfig.getAutoSellWeaponLevelList();
        int dropLevel = levelConfig.getDropLevel();
        Map<Integer, FellingTreesWeaponsConfig> weaponsConfigMap = config.getWeaponsConfigMap();

        for (FellingTreesReward reward : rewardList) {
            List<FellingTreesEquip> tmpEquipList = reward.getNormalEquipList();
            for (int i = 0; i < tmpEquipList.size(); i++) {
                FellingTreesEquip tmpEquip = tmpEquipList.get(i);

                // 满级的都不会熔炼
                if (tmpEquip.getLv() >= maxDropEquipLevel) {
                    continue;
                }

                int quality = weaponsConfigMap.get(tmpEquip.getEquipId()).getQuality();

                // 强制熔炼判断
                if (quality <= autoSellWeaponLevelList.size() && tmpEquip.getLv() < dropLevel - autoSellWeaponLevelList.get(quality - 1)) {
                    // 转化成金币
                    FellingTreesLevelConfig tmpLevelConfig = levelConfigMap.get(tmpEquip.getLv());
                    reward.setGold(reward.getGold().add(tmpLevelConfig.getSellGold()));
                    tmpEquipList.remove(i--);
                    recycleCount++;
                }
            }
        }

        // 引导奖励
        if (userData.getTopLevel() == 0) {
            FellingTreesReward reward;
            if (rewardList.size() > 0) {
                reward = rewardList.get(rewardList.size() - 1);
            } else {
                reward = new FellingTreesReward(1);
                rewardList.add(reward);
            }
            reward.setGold(reward.getGold().add(config.getGuideGoldCount()));
            for (int i = 0; i < config.getGuideEquipIds().size(); i++) {
                int tmpId = config.getGuideEquipIds().get(i);
                int tmpLv = config.getGuideEquipLvs().get(i);
                reward.getNormalEquipList().add(new FellingTreesEquip(-1L, tmpId, tmpLv, tmpLv, false));
            }
        }

        // 汇总奖励
        FellingTreesReward allReward = new FellingTreesReward();
        allReward.setLv(cutDownLv);
        for (FellingTreesReward reward : rewardList) {
            allReward.getNormalEquipList().addAll(reward.getNormalEquipList());
            allReward.getItems().addProperty(reward.getItems());
            allReward.getSpecialEquips().addProperty(reward.getSpecialEquips());
            allReward.setGold(allReward.getGold().add(reward.getGold()));
            allReward.getDaoQi().addProperty(reward.getDaoQi());
        }

        // 扣体力
        removeEnergy(config, userData, costEnergy);

        // 扣buff次数
        ConcurrentHashMap<Integer, Integer> newBuffMap = new ConcurrentHashMap<>();
        for (Map.Entry<Integer, Integer> entry : userData.getBuffMap().entrySet()) {
            if (entry.getValue() > 1) {
                newBuffMap.put(entry.getKey(), entry.getValue() - 1);
            }
        }
        userData.setBuffMap(newBuffMap);

        // 加奖励
        addNormalEquip(config, userData, allReward.getNormalEquipList(), eFellingTreesWay.Play.getValue()); // 捡法宝
        SpecialEquipAddResultHelper specialEquipAddResultHelper = addSpecialEquip(config, userData, allReward.getSpecialEquips(), eFellingTreesWay.Play.getValue());// 捡灵宝
        if (specialEquipAddResultHelper.getDaoqiClearItemCount() > 0) {
            allReward.getItems().addProperty(config.getDaoqiClearItemId(), BigInteger.valueOf(specialEquipAddResultHelper.getDaoqiClearItemCount()));
        }
        addDaoQi(config, userData, allReward.getDaoQi(), eFellingTreesWay.Play.getValue());// 捡道器
        addItem(config, userData, allReward.getItems(), eFellingTreesWay.Play.getValue()); // 捡材料
        addGold(config, userData, allReward.getGold(), eFellingTreesWay.Play.getValue()); // 捡金币
        player.getModule(CurrencyModule.class).addCurrency(scoreReward, eLogMoneyType.FellingTreesActivity, eLogMoneyType.FellingTreesActivityPlayGetScore); // 加积分

        // 修改数据
        userData.setLastLevel(lastLv);
        userData.setLastHp(lastHp);
        int newTopLv = cutDownLv;
        if (newTopLv > userData.getTopLevel()) {
            userData.setTopLevel(newTopLv);
            player.notifyListener(eGamePlayerEventType.FellingTreesLevelRank.getValue(), FellingTreesLevelArgs.create(config, userData));
            player.notifyListener(eGamePlayerEventType.FellingTreesLevelCondition.getValue(), newTopLv);
        }

        if (isSkipGuide){
            //获得奖励后,加入客户端展示
            FellingTreesReward specialEquipGuideReward = finishSpecialEquipGuideReward();
            if (specialEquipGuideReward != null) {
                allReward.getSpecialEquips().addProperty(specialEquipGuideReward.getSpecialEquips());
            }
            FellingTreesReward rabbitGuideReward = finishRabbitGuideReward();
            if (rabbitGuideReward != null) {
                allReward.getItems().addProperty(rabbitGuideReward.getItems());
            }
            FellingTreesReward daoqiGuideReward = finishDaoqiGuideReward();
            if (daoqiGuideReward != null) {
                allReward.getItems().addProperty(daoqiGuideReward.getItems());
            }
        }

        FellingTreesProto.FellingTreesPlayRespMsg.Builder builder = FellingTreesProto.FellingTreesPlayRespMsg.newBuilder();
        builder.setRet(0);
        if (skip) {
            // 跳过动画可以节约流量
            if (rewardList.size() > 0) {
                builder.addReward(FellingTreesPb.parseFellingTreesRewardMsg(config, allReward));
            }
        } else {
            for (FellingTreesReward reward : rewardList) {
                builder.addReward(FellingTreesPb.parseFellingTreesRewardMsg(config, reward));
            }
        }
        builder.setUserData(FellingTreesPb.parseFellingTreesUserDataMsg(userData));
        builder.setCutTimes(attackTimes);
        builder.addAllEquip(FellingTreesPb.parseFellingTreesEquipMsgList(userData.getEquipMap().values()));
        builder.addAllItem(FellingTreesPb.parseFellingTreesItemMsgList(userData.getItems()));
        builder.setRecycleCount(recycleCount);
        builder.setDamage(perAttack.toString());
        builder.setScore(scoreLong);
        builder.setMoonStoneTranCount(specialEquipAddResultHelper.getTotalTranCount());
        player.sendPacket(ClientProtocol.U_FELLING_TREES_PLAY, builder);

        userData.setUpdateOption();

        // 日志
        AutoLogMgr.add(new LogFellingTreesPlay(
                config.getActivityInfo().getActivityId(),
                getUserId(),
                userData.getAttack().toString(),
                logDamage.toString(),
                lastLv,
                lastHp.toString(),
                allReward.getGold().toString(),
                recycleCount,
                allReward.getNormalEquipList(),
                PropertyHelper.parsePropertyToString(allReward.getSpecialEquips()),
                PropertyHelper.parsePropertyToString(allReward.getItems()),
                userData.getBuffMap(),
                costEnergy,
                PropertyHelper.parsePropertyToString(allReward.getDaoQi())
        ));
        AutoLogMgr.add(new LogFellingTreesEnergy(
                config.getActivityInfo().getActivityId(),
                getUserId(),
                LogFellingTreesEnergy.TYPE_CUT_ENERGY,
                LogFellingTreesEnergy.SON_TYPE_CUT,
                fellingTreesUserData.getEnergy() - logEnergy,
                fellingTreesUserData.getEnergy()
        ));

        return 0;
    }

    /**
     * 打开法宝界面
     */
    public int openEquipList() {
        FellingTreesUserData userData = getUserData();

        // 自动装备（这个功能不要了）
        List<Integer> autoEquipList = new ArrayList<>();

        FellingTreesProto.FellingTreesGetEquipDataRespMsg.Builder builder = FellingTreesProto.FellingTreesGetEquipDataRespMsg.newBuilder();
        builder.setRet(0);
        builder.addAllEquip(FellingTreesPb.parseFellingTreesEquipMsgList(userData.getEquipMap().values()));
        builder.addAllPos(FellingTreesPb.parseFellingTreesPosMsgList(userData.getEquipPosArr()));
        builder.addAllAutoWearIndex(autoEquipList);
        builder.setUserData(FellingTreesPb.parseFellingTreesUserDataMsg(userData));
        player.sendPacket(ClientProtocol.U_FELLING_TREES_GET_EQUIP_LIST, builder);

        return 0;
    }

    /**
     * 开装备栏
     */
    public int openEquipPos(int index) {
        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();
        FellingTreesUserData userData = getUserData();

        long[] equipPosArr = userData.getEquipPosArr();

        // 格子不存在
        if (index < 0 || index >= equipPosArr.length) {
            return GameErrorCode.E_FELLING_TREES_EQUIP_POS_NO_EXIST;
        }

        // 已开启
        if (equipPosArr[index] >= 0) {
            return GameErrorCode.E_FELLING_TREES_EQUIP_POS_HAD_UNLOCK;
        }

        // 拿已解锁格子数
        int unlockPosCount = getUnlockPosCount(config, userData.getEquipPosArr());

        // 拿消耗
        int costIndex = unlockPosCount;
        List<BigInteger> costList = config.getUnlockPosCostList();
        BigInteger cost = costList.get(Math.min(costIndex, costList.size() - 1));

        // 扣消耗
        if (!removeGold(config, userData, cost, eFellingTreesWay.UnlockPos.getValue())) {
            return GameErrorCode.E_FELLING_TREES_ITEM_NO_ENOUGH;
        }

        // 开格子
        equipPosArr[index] = 0;

        // 返回
        FellingTreesProto.FellingTreesOpenPosRespMsg.Builder builder = FellingTreesProto.FellingTreesOpenPosRespMsg.newBuilder();
        builder.setRet(0);
        builder.addAllPos(FellingTreesPb.parseFellingTreesPosMsgList(userData.getEquipPosArr()));
        builder.setUserData(FellingTreesPb.parseFellingTreesUserDataMsg(userData));
        player.sendPacket(ClientProtocol.U_FELLING_TREES_OPEN_EQUIP_POS, builder);

        userData.setUpdateOption();

        // 日志
        AutoLogMgr.add(new LogFellingTreesUnlockPos(
                config.getActivityInfo().getActivityId(),
                getUserId(),
                index
        ));

        return 0;
    }

    /**
     * 重置装备栏
     */
    public int resetEquipPos() {
        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();
        FellingTreesUserData userData = getUserData();
        long[] equipPosArr = userData.getEquipPosArr();

        int unlockPosCount = getUnlockPosCount(config, equipPosArr);

        // 没有格子需要重置
        if (unlockPosCount <= 0) {
            return GameErrorCode.E_FELLING_TREES_NO_OPEN_POS;
        }

        // 计算重置返还
        BigInteger sum = BigInteger.ZERO;
        List<BigInteger> costList = config.getUnlockPosCostList();
        for (int i = 0; i < unlockPosCount; i++) {
            sum = sum.add(costList.get(Math.min(i, costList.size() - 1)));
        }

        // 扣消耗
        Property resetPosCost = PropertyHelper.parseStringToProperty(config.getResetPosCost());
        if (!player.getModule(CurrencyModule.class).removeCurrency(resetPosCost, eLogMoneyType.FellingTreesActivity, eLogMoneyType.FellingTreesActivityResetEquipPos)) {
            return GameErrorCode.E_FELLING_TREES_ITEM_NO_ENOUGH;
        }

        // 重置
        int index = -1;
        for (int[] arr : config.getPosConfig()) {
            for (int intValue : arr) {
                index++;
                equipPosArr[index] = intValue;
            }
        }

        // 加金币
        addGold(config, userData, sum, eFellingTreesWay.ResetPos.getValue());

        // 重新计算战力
        calcAttack(config, userData);

        // 返回
        FellingTreesProto.FellingTreesResetPosRespMsg.Builder builder = FellingTreesProto.FellingTreesResetPosRespMsg.newBuilder();
        builder.setRet(0);
        builder.addAllPos(FellingTreesPb.parseFellingTreesPosMsgList(equipPosArr));
        builder.setUserData(FellingTreesPb.parseFellingTreesUserDataMsg(userData));
        player.sendPacket(ClientProtocol.U_FELLING_TREES_RESET_EQUIP_POS, builder);

        userData.setUpdateOption();

        // 日志
        AutoLogMgr.add(new LogFellingTreesUnlockPos(
                config.getActivityInfo().getActivityId(),
                getUserId(),
                -1
        ));

        return 0;
    }

    /**
     * 穿装备
     */
    public int wearEquip(long uid, int index) {

        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();
        FellingTreesUserData userData = getUserData();

        long[] equipPosArr = userData.getEquipPosArr();
        if (index < 0 || index >= equipPosArr.length) {
            return GameErrorCode.E_FELLING_TREES_EQUIP_POS_NO_EXIST;
        }

        // 格子未开启
        if (equipPosArr[index] == -1) {
            return GameErrorCode.E_FELLING_TREES_EQUIP_POS_NO_UNLOCK;
        }

        if (uid == 0) {
            // 【卸下】

            equipPosArr[index] = 0;
        } else {
            // 【装备】

            // 拿操作的装备
            FellingTreesEquip operateEquip = userData.getEquipMap().get(uid);
            if (operateEquip == null) {
                return GameErrorCode.E_FELLING_TREES_EQUIP_NO_EXIST;
            }
            // 操作装备是否已经穿戴
            int operateEquipPos = -1;
            for (int i = 0; i < equipPosArr.length; i++) {
                long equipUid = equipPosArr[i];
                if (equipUid == uid) {
                    operateEquipPos = i;
                    break;
                }
            }
            // 操作装备是否是灵宝或者道器
            FellingTreesWeaponsConfig operateEquipConfig = config.getWeaponsConfigMap().get(operateEquip.getEquipId());
            boolean operateEquipIsSpecial = operateEquipConfig.getType() == eFellingTreesEquipType.SpecialEquip.getValue() || operateEquipConfig.getType() == eFellingTreesEquipType.DaoQi.getValue();

            // 穿戴位置是否是灵宝或者道器
            boolean targetEquipIsSpecial = false;
            long targetUid = equipPosArr[index];
            if (targetUid > 0) {
                FellingTreesEquip targetEquip = userData.getEquipMap().get(targetUid);
                FellingTreesWeaponsConfig targetEquipConfig = config.getWeaponsConfigMap().get(targetEquip.getEquipId());
                targetEquipIsSpecial = targetEquipConfig.getType() == eFellingTreesEquipType.SpecialEquip.getValue() || targetEquipConfig.getType() == eFellingTreesEquipType.DaoQi.getValue();
            }

            // 穿戴灵宝
            if (operateEquipIsSpecial && operateEquipPos == -1) {
                // 穿戴位置原本不是灵宝 && 穿戴数量达到上限
                if (!targetEquipIsSpecial && isWearEquipLimit(config, userData, operateEquipConfig.getType())) {
                    return GameErrorCode.E_FELLING_TREES_SPECIAL_EQUIP_WEAR_LIMIT;
                }
            }

            if (operateEquipPos != -1) {
                // 装备栏互换
                equipPosArr[operateEquipPos] = equipPosArr[index];
                equipPosArr[index] = uid;
            } else {
                // 装备上去
                equipPosArr[index] = uid;
            }
        }

        // 重新计算攻击力
        calcAttack(config, userData);

        // 返回
        FellingTreesProto.FellingTreesWearEquipRespMsg.Builder builder = FellingTreesProto.FellingTreesWearEquipRespMsg.newBuilder();
        builder.setRet(0);
        builder.addAllPos(FellingTreesPb.parseFellingTreesPosMsgList(userData.getEquipPosArr()));
        builder.setUserData(FellingTreesPb.parseFellingTreesUserDataMsg(userData));
        player.sendPacket(ClientProtocol.U_FELLING_TREES_WEAR_EQUIP, builder);

        userData.setUpdateOption();
        return 0;
    }

    /**
     * 强化装备
     */
    public int upgradeEquip(long uid) {
        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();
        FellingTreesUserData userData = getUserData();

        // 装备不存在
        FellingTreesEquip equip = userData.getEquipMap().get(uid);
        if (equip == null) {
            return GameErrorCode.E_FELLING_TREES_EQUIP_NO_EXIST;
        }

        // 装备类型
        FellingTreesWeaponsConfig weaponsConfig = config.getWeaponsConfigMap().get(equip.getEquipId());

        if (weaponsConfig.getType() == eFellingTreesEquipType.Normal.getValue()) {
            // 【法宝升级】

            // 升级次数上限
            if (equip.getLv() - equip.getBaseLv() >= config.getEquipMaxUpgradeLv()) {
                return GameErrorCode.E_FELLING_TREES_EQUIP_UPGRADE_LIMIT;
            }

            // 等级上限
            if (equip.getLv() >= config.getLevelConfigMap().size()) {
                return GameErrorCode.E_FELLING_TREES_EQUIP_LV_MAX;
            }

            // 扣消耗
            BigInteger cost = getUpgradeGold(config, equip.getBaseLv(), equip.getLv());
            if (!removeGold(config, userData, cost, eFellingTreesWay.EquipUpgrade.getValue())) {
                return GameErrorCode.E_FELLING_TREES_ITEM_NO_ENOUGH;
            }

        } else if (weaponsConfig.getType() == eFellingTreesEquipType.SpecialEquip.getValue()) {

            // 【灵宝升级】

            // 等级上限
            if (equip.getLv() >= config.getSpecialEquipMaxLevel()) {
                return GameErrorCode.E_FELLING_TREES_EQUIP_LV_MAX;
            }

            // 扣消耗
            long costCount = config.getSpecialEquipUpgradeCost().get(equip.getLv() - 1);
            Property cost = new Property();
            cost.addProperty(equip.getEquipId(), BigInteger.valueOf(costCount));
            if (!removeItem(config, userData, cost, eFellingTreesWay.EquipUpgrade.getValue())) {
                return GameErrorCode.E_FELLING_TREES_ITEM_NO_ENOUGH;
            }

        } else {
            // 其他类型不支持强化
            return GameErrorCode.E_FELLING_TREES_PARAM_ERROR;
        }

        // 加等级
        equip.setLv(equip.getLv() + 1);

        // 重新计算法力值
        calcAttack(config, userData);

        // 返回
        FellingTreesProto.FellingTreesUpgradeEquipRespMsg.Builder builder = FellingTreesProto.FellingTreesUpgradeEquipRespMsg.newBuilder();
        builder.setRet(0);
        builder.setUserData(FellingTreesPb.parseFellingTreesUserDataMsg(userData));
        // 灵宝
        if (weaponsConfig.getType() == eFellingTreesEquipType.SpecialEquip.getValue()) {
            long count = userData.getItems().getCountByGoodsId(equip.getEquipId()).longValue();
            builder.addItem(FellingTreesProto.FellingTreesItemMsg.newBuilder().setItemId(equip.getEquipId()).setNum(count));
        }
        builder.setEquip(FellingTreesPb.parseFellingTreesEquipMsg(equip));
        player.sendPacket(ClientProtocol.U_FELLING_TREES_UPGRADE_EQUIP, builder);

        userData.setUpdateOption();

        // 日志
        AutoLogMgr.add(new LogFellingTreesEquip(
                config.getActivityInfo().getActivityId(),
                getUserId(),
                LogFellingTreesEquip.TYPE_UPGRADE,
                equip,
                eFellingTreesWay.EquipUpgrade.getValue(),
                weaponsConfig.getType()
        ));

        return 0;
    }

    /**
     * 锁定装备
     */
    public int lockEquip(long uid, boolean lock) {

        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();
        FellingTreesUserData userData = getUserData();

        FellingTreesEquip equip = userData.getEquipMap().get(uid);
        if (equip == null) {
            return GameErrorCode.E_FELLING_TREES_EQUIP_NO_EXIST;
        }

        // 灵宝、道器无法解锁
        if (!lock) {
            FellingTreesWeaponsConfig weaponsConfig = config.getWeaponsConfigMap().get(equip.getEquipId());
            if (weaponsConfig.getType() == eFellingTreesEquipType.SpecialEquip.getValue()
                    || weaponsConfig.getType() == eFellingTreesEquipType.DaoQi.getValue()) {
                return GameErrorCode.E_FELLING_TREES_EQUIP_CAN_NOT_UNLOCK;
            }
        }

        // 修改状态
        equip.setLock(lock);

        FellingTreesProto.FellingTreesLockEquipRespMsg.Builder builder = FellingTreesProto.FellingTreesLockEquipRespMsg.newBuilder();
        builder.setRet(0);
        builder.setEquip(FellingTreesPb.parseFellingTreesEquipMsg(equip));
        player.sendPacket(ClientProtocol.U_FELLING_TREES_LOCK_EQUIP, builder);

        userData.setUpdateOption();
        return 0;
    }

    /**
     * 熔炼装备
     */
    public int recycleEquip(List<Long> uidList) {

        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();
        FellingTreesUserData userData = getUserData();

        Map<Long, FellingTreesEquip> equipMap = userData.getEquipMap();

        // ID不能重复
        if (uidList.size() != new HashSet<>(uidList).size()) {
            return GameErrorCode.E_FELLING_TREES_EQUIP_REPEATED;
        }

        // 身上穿的
        Set<Long> wearSet = new HashSet<>();
        for (long uid : userData.getEquipPosArr()) {
            if (uid > 0) {
                wearSet.add(uid);
            }
        }

        // 看看装备有没有在、有没有锁定
        for (long uid : uidList) {
            FellingTreesEquip equip = equipMap.get(uid);
            if (equip == null) {
                return GameErrorCode.E_FELLING_TREES_EQUIP_NO_EXIST;
            }
            if (equip.isLock()) {
                return GameErrorCode.E_FELLING_TREES_EQUIP_HAD_LOCK;
            }
            if (wearSet.contains(uid)) {
                return GameErrorCode.E_FELLING_TREES_RECYCLE_EQUIP_HAD_WEAR;
            }
        }

        List<FellingTreesEquip> logEquipList = new ArrayList<>();

        // 计算卖多少钱
        BigInteger sum = BigInteger.ZERO;
        ConcurrentHashMap<Long, FellingTreesEquip> copyMap = new ConcurrentHashMap<>(equipMap);
        for (long uid : uidList) {
            // 移除
            FellingTreesEquip removeEquip = copyMap.remove(uid);
            // 算钱：基础价格 + 强化消耗
            FellingTreesLevelConfig levelConfig = config.getLevelConfigMap().get(removeEquip.getBaseLv()); // 这里是基础等级
            sum = sum.add(levelConfig.getSellGold());
            if (removeEquip.getLv() != removeEquip.getBaseLv()) {
                for (int lv = removeEquip.getBaseLv(); lv < removeEquip.getLv(); lv++) {
                    sum = sum.add(getUpgradeGold(config, removeEquip.getBaseLv(), lv));
                }
            }

            logEquipList.add(removeEquip);
        }

        // 修改数据
        userData.setEquipMap(copyMap);
        addGold(config, userData, sum, eFellingTreesWay.Recycle.getValue());

        // 返回
        FellingTreesProto.FellingTreesRecycleEquipRespMsg.Builder builder = FellingTreesProto.FellingTreesRecycleEquipRespMsg.newBuilder();
        builder.setRet(0);
        builder.addAllEquip(FellingTreesPb.parseFellingTreesEquipMsgList(userData.getEquipMap().values()));
        builder.setUserData(FellingTreesPb.parseFellingTreesUserDataMsg(userData));
        player.sendPacket(ClientProtocol.U_FELLING_TREES_RECYCLE_EQUIP, builder);

        userData.setUpdateOption();

        // 日志
        for (FellingTreesEquip equip : logEquipList) {
            AutoLogMgr.add(new LogFellingTreesEquip(
                    config.getActivityInfo().getActivityId(),
                    getUserId(),
                    LogFellingTreesEquip.TYPE_RECYCLE,
                    equip,
                    eFellingTreesWay.Recycle.getValue(),
                    config.getWeaponsConfigMap().get(equip.getEquipId()).getType()
            ));
        }

        return 0;
    }

    /**
     * 制作buff药
     */
    public int makeBuffItem(int itemId) {
        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();
        FellingTreesUserData userData = getUserData();

        // 未解锁
        if (userData.getTopLevel() < config.getUnlockRabbitNeedLevel()) {
            return GameErrorCode.E_FELLING_TREES_LEVEL_LIMIT;
        }

        // 仙丹不存在
        FellingTreesElixirConfig elixirConfig = config.getElixirConfigMap().get(itemId);
        if (elixirConfig == null) {
            return GameErrorCode.E_FELLING_TREES_BUFF_ITEM_NO_EXIST;
        }

        // 扣消耗
        Property cost = elixirConfig.getMaterialsProp();
        if (!removeItem(config, userData, cost, eFellingTreesWay.MakeBuffItem.getValue())) {
            return GameErrorCode.E_FELLING_TREES_ITEM_NO_ENOUGH;
        }

        // 加道具
        Property property = new Property();
        property.addProperty(itemId, BigInteger.ONE);
        addItem(config, userData, property, eFellingTreesWay.MakeBuffItem.getValue());

        // 返回
        FellingTreesProto.FellingTreesMakeBuffItemRespMsg.Builder builder = FellingTreesProto.FellingTreesMakeBuffItemRespMsg.newBuilder();
        builder.setRet(0);
        builder.addAllItem(FellingTreesPb.parseFellingTreesItemMsgList(userData.getItems()));
        builder.setUserData(FellingTreesPb.parseFellingTreesUserDataMsg(userData));
        player.sendPacket(ClientProtocol.U_FELLING_TREES_MAKE_BUFF_ITEM, builder);

        userData.setUpdateOption();

        return 0;
    }

    /**
     * 装备词条洗练
     */
    public int equipClear(long uniqueId) {
        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();
        FellingTreesUserData userData = getUserData();
        FellingTreesEquip equip = userData.getEquipMap().get(uniqueId);
        if (equip == null) {
            return GameErrorCode.E_FELLING_TREES_EQUIP_NO_EXIST;
        }
        // 目前仅支持道器洗练,后续若支持其他装备类型词条需配置处理
        FellingTreesWeaponsConfig weaponsConfig = config.getWeaponsConfigMap().get(equip.getEquipId());
        if (weaponsConfig.getType() != eFellingTreesEquipType.DaoQi.getValue()) {
            return GameErrorCode.E_FELLING_TREES_PARAM_ERROR;
        }
        // 当前词条数
        List<FellingTreesEquipParam> paramList = equip.getParamList();
        if (paramList.size() == 0) {
            return GameErrorCode.E_FELLING_TREES_PARAM_ERROR;
        }
        // 获取消耗
        String[] paramSplit = weaponsConfig.getParam().split("\\|");
        String itemParam = paramSplit[paramList.size() - 1];
        String[] split = itemParam.split(";");
        // 最大千分比
        int maxValue = Integer.parseInt(split[1]);
        // 单次洗练最大千分比
        int maxClearValue = Integer.parseInt(split[2]);
        // 单次洗练消耗
        int clearCount = Integer.parseInt(split[3]);
        // 消耗id
        int itemId = config.getDaoqiClearItemId();
        if (!removeItem(config, userData, new Property(itemId, clearCount), eFellingTreesWay.EquipClear.getValue())) {
            return GameErrorCode.E_FELLING_TREES_ITEM_NO_ENOUGH;
        }
        int randomValue = 0;
        int randomType = 0;
        // 洗练
        String[] clearParamConfig = config.getMaxDaoqiClearParam().split("\\|");
        // 总权重
        int sumWeight = 0;
        for (String clearParam : clearParamConfig) {
            String[] param = clearParam.split(";");
            sumWeight += Integer.parseInt(param[1]);
        }
        // 随机一个权重
        int randomWeight = (int) (Math.random() * sumWeight);
        // 当前权重
        int curWeight = 0;
        for (String clearParam : clearParamConfig) {
            String[] param = clearParam.split(";");
            curWeight += Integer.parseInt(param[1]);
            if (randomWeight < curWeight) {
                randomValue = Integer.parseInt(param[0]);
                randomType = Integer.parseInt(param[2]);
                break;
            }
        }
        BigInteger resultValue = new BigDecimal(BigInteger.valueOf(randomValue).multiply(BigInteger.valueOf(maxClearValue)))
                .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).toBigInteger();
        // 更新词条
        daoQiParamAddOffset(equip, resultValue.intValue(), maxValue);

        // 判断是否有穿戴
        // 操作装备是否已经穿戴
        int operateEquipPos = -1;
        for (int i = 0; i < userData.getEquipPosArr().length; i++) {
            long equipUid = userData.getEquipPosArr()[i];
            if (equipUid == uniqueId) {
                operateEquipPos = i;
                break;
            }
        }
        if (operateEquipPos != -1) {
            // 重新计算攻击力
            calcAttack(config, userData);
        }
        userData.setUpdateOption();

        FellingTreesProto.FellingTreesEquipClearRespMsg.Builder builder = FellingTreesProto.FellingTreesEquipClearRespMsg.newBuilder();
        builder.setRet(0);
        builder.setEquip(FellingTreesPb.parseFellingTreesEquipMsg(equip));
        builder.addAllItem(FellingTreesPb.parseFellingTreesItemMsgList(userData.getItems()));
        builder.setUserData(FellingTreesPb.parseFellingTreesUserDataMsg(userData));
        builder.setClearType(randomType);
        player.sendPacket(ClientProtocol.U_FELLING_TREES_EQUIP_CLEAR_PARAM, builder);

        return 0;
    }

    /**
     * 完成玉兔捣药引导
     */
    public int finishRabbitGuide() {
        FellingTreesUserData userData = getUserData();
        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();

        if (userData.getTopLevel() < config.getUnlockRabbitNeedLevel()) {
            return GameErrorCode.E_FELLING_TREES_LEVEL_LIMIT;
        }

        if (userData.isRabbitGuide()) {
            return GameErrorCode.E_FELLING_TREES_HAD_GET_GUIDE_REWARD;
        }

        String guideReward = config.getRabbitGuideReward();
        Property property = PropertyHelper.parseStringToProperty(guideReward);

        // 加奖励
        addItem(config, userData, property, eFellingTreesWay.GuideReward.getValue());

        // 改状态
        userData.setRabbitGuide(true);

        FellingTreesProto.FellingTreesGuideFinishRespMsg.Builder builder = FellingTreesProto.FellingTreesGuideFinishRespMsg.newBuilder();
        builder.setRet(0);
        builder.setRabbitReward(guideReward);
        builder.addAllItem(FellingTreesPb.parseFellingTreesItemMsgList(userData.getItems()));
        builder.addAllEquip(FellingTreesPb.parseFellingTreesEquipMsgList(userData.getEquipMap().values()));
        builder.setUserData(FellingTreesPb.parseFellingTreesUserDataMsg(userData));
        player.sendPacket(ClientProtocol.U_FELLING_TREES_FINISH_GUIDE, builder);

        userData.setUpdateOption();
        return 0;
    }

    public FellingTreesReward finishRabbitGuideReward() {
        FellingTreesUserData userData = getUserData();
        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();

        if (userData.getTopLevel() < config.getUnlockRabbitNeedLevel()) {
            return null;
        }

        if (userData.isRabbitGuide()) {
            return null;
        }

        String guideReward = config.getRabbitGuideReward();
        Property property = PropertyHelper.parseStringToProperty(guideReward);

        // 加奖励
        addItem(config, userData, property, eFellingTreesWay.GuideReward.getValue());

        // 改状态
        userData.setRabbitGuide(true);

        userData.setUpdateOption();

        FellingTreesReward showReward = new FellingTreesReward();
        showReward.getItems().addProperty(property);

        return showReward;
    }

    /**
     * 完成灵宝引导
     */
    public int finishSpecialEquipGuide() {
        FellingTreesUserData userData = getUserData();
        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();

        if (userData.getTopLevel() < config.getSpecialEquipUnlockLv()) {
            return GameErrorCode.E_FELLING_TREES_LEVEL_LIMIT;
        }

        if (userData.isSpecialEquipGuide()) {
            return GameErrorCode.E_FELLING_TREES_HAD_GET_GUIDE_REWARD;
        }

        // 转化一下客户端看的奖励
        Property configReward = PropertyHelper.parseStringToProperty(config.getSpecialEquipUnlockReward());
        List<FellingTreesEquip> clientShowList = new ArrayList<>();
        for (Map.Entry<Integer, BigInteger> entry : configReward.getGoods().entrySet()) {
            int equipId = entry.getKey();
            int count = entry.getValue().intValue();
            for (int i = 0; i < count; i++) {
                clientShowList.add(FellingTreesEquip.createSpecialEquip(equipId));
            }
        }

        // 加奖励
        addSpecialEquip(config, userData, configReward, eFellingTreesWay.GuideReward.getValue());

        // 改状态
        userData.setSpecialEquipGuide(true);

        FellingTreesProto.FellingTreesGuideFinishRespMsg.Builder builder = FellingTreesProto.FellingTreesGuideFinishRespMsg.newBuilder();
        builder.setRet(0);
        builder.addAllEquipReward(FellingTreesPb.parseFellingTreesEquipMsgList(clientShowList));
        builder.addAllItem(FellingTreesPb.parseFellingTreesItemMsgList(userData.getItems()));
        builder.addAllEquip(FellingTreesPb.parseFellingTreesEquipMsgList(userData.getEquipMap().values()));
        builder.setUserData(FellingTreesPb.parseFellingTreesUserDataMsg(userData));
        player.sendPacket(ClientProtocol.U_FELLING_TREES_FINISH_GUIDE, builder);

        userData.setUpdateOption();
        return 0;
    }

    public FellingTreesReward finishSpecialEquipGuideReward() {
        FellingTreesUserData userData = getUserData();
        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();

        if (userData.getTopLevel() < config.getSpecialEquipUnlockLv()) {
            return null;
        }

        if (userData.isSpecialEquipGuide()) {
            return null;
        }

        // 转化一下客户端看的奖励
        Property configReward = PropertyHelper.parseStringToProperty(config.getSpecialEquipUnlockReward());

        // 加奖励
        addSpecialEquip(config, userData, configReward, eFellingTreesWay.GuideReward.getValue());
        // 改状态
        userData.setSpecialEquipGuide(true);
        userData.setUpdateOption();

        FellingTreesReward showReward = new FellingTreesReward();
        for (Map.Entry<Integer, BigInteger> entry : configReward.getGoods().entrySet()) {
            int equipId = entry.getKey();
            int count = entry.getValue().intValue();
            for (int i = 0; i < count; i++) {
                showReward.getNormalEquipList().add(FellingTreesEquip.createSpecialEquip(equipId));
            }
        }

        return showReward;
    }

    /**
     * 完成道器引导(月灵石奖励)
     */
    public int finishDaoqiGuide() {
        FellingTreesUserData userData = getUserData();
        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();

        if (userData.isDaoqiGuide()) {
            return GameErrorCode.E_FELLING_TREES_HAD_GET_GUIDE_REWARD;
        }

        if (!haveDaoqi(config, userData)) {
            return GameErrorCode.E_FELLING_TREES_LEVEL_LIMIT;
        }

        String guideReward = config.getDaoqiUnlockReward();
        Property property = PropertyHelper.parseStringToProperty(guideReward);

        // 加奖励
        addItem(config, userData, property, eFellingTreesWay.GuideReward.getValue());

        // 改状态
        userData.setDaoqiGuide(true);

        FellingTreesProto.FellingTreesGuideFinishRespMsg.Builder builder = FellingTreesProto.FellingTreesGuideFinishRespMsg.newBuilder();
        builder.setRet(0);
        builder.setDaoqiReward(guideReward);
        builder.addAllItem(FellingTreesPb.parseFellingTreesItemMsgList(userData.getItems()));
        builder.addAllEquip(FellingTreesPb.parseFellingTreesEquipMsgList(userData.getEquipMap().values()));
        builder.setUserData(FellingTreesPb.parseFellingTreesUserDataMsg(userData));
        player.sendPacket(ClientProtocol.U_FELLING_TREES_FINISH_GUIDE, builder);

        userData.setUpdateOption();
        return 0;
    }

    public FellingTreesReward finishDaoqiGuideReward() {
        FellingTreesUserData userData = getUserData();
        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();

        if (userData.isDaoqiGuide()) {
            return null;
        }

        if (!haveDaoqi(config, userData)) {
            return null;
        }

        String guideReward = config.getDaoqiUnlockReward();
        Property property = PropertyHelper.parseStringToProperty(guideReward);

        // 加奖励
        addItem(config, userData, property, eFellingTreesWay.GuideReward.getValue());

        // 改状态
        userData.setDaoqiGuide(true);

        userData.setUpdateOption();

        FellingTreesReward showReward = new FellingTreesReward();
        showReward.getItems().addProperty(property);

        return showReward;
    }

    /**
     * 使用活动道具
     */
    public int useItem(int itemId, int count) {
        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();
        FellingTreesUserData userData = getUserData();

        // 数量不能太假
        if (count <= 0 || count >= 10000) {
            return GameErrorCode.E_BAG_ITEM_CAN_NO_USE;
        }

        // 按类型使用
        int ret = -1;
        boolean isEnergyItem = false;
        if (itemId == config.getEnergyItemId()) {
            // [体力]
            isEnergyItem = true;
            ret = useEnergyItem(config, userData, itemId, count);
        } else {
            // [buff道具]
            ret = useBuffItem(config, userData, itemId, count);
        }
        if (ret != 0) {
            return ret;
        }

        // 返回
        FellingTreesProto.FellingTreesUseItemRespMsg.Builder builder = FellingTreesProto.FellingTreesUseItemRespMsg.newBuilder();
        builder.setRet(0);
        builder.setUserData(FellingTreesPb.parseFellingTreesUserDataMsg(userData));
        if (!isEnergyItem) {
            builder.setItem(FellingTreesProto.FellingTreesItemMsg.newBuilder()
                    .setItemId(itemId)
                    .setNum(userData.getItems().getCountByGoodsId(itemId).longValue()));
        }
        player.sendPacket(ClientProtocol.U_FELLING_TREES_USE_ITEM, builder);

        userData.setUpdateOption();
        return 0;
    }

    // ============ 道具整理下 ============

    private void addItem(FellingTreesConfig config, FellingTreesUserData userData, Property change, int way) {
        userData.getItems().addProperty(change);

        // 日志
        for (Map.Entry<Integer, BigInteger> entry : change.getGoods().entrySet()) {
            Integer itemId = entry.getKey();
            BigInteger count = entry.getValue();
            AutoLogMgr.add(new LogFellingTreesItem(
                    config.getActivityInfo().getActivityId(),
                    getUserId(),
                    itemId,
                    count.toString(),
                    userData.getItems().getCountByGoodsId(itemId).toString(),
                    way
            ));
        }
    }

    private boolean removeItem(FellingTreesConfig config, FellingTreesUserData userData, Property change, int way) {
        Property items = userData.getItems();
        // 看看够不够
        for (Map.Entry<Integer, BigInteger> entry : change.getGoods().entrySet()) {
            Integer itemId = entry.getKey();
            BigInteger count = entry.getValue();
            if (items.getCountByGoodsId(itemId).compareTo(count) < 0) {
                return false;
            }
        }
        // 扣道具
        for (Map.Entry<Integer, BigInteger> entry : change.getGoods().entrySet()) {
            Integer itemId = entry.getKey();
            BigInteger count = entry.getValue();
            items.removeProperty(itemId, count);


            // 日志
            AutoLogMgr.add(new LogFellingTreesItem(
                    config.getActivityInfo().getActivityId(),
                    getUserId(),
                    itemId,
                    BigInteger.valueOf(-1).multiply(count).toString(),
                    items.getCountByGoodsId(itemId).toString(),
                    way
            ));
        }
        return true;
    }

    private void addGold(FellingTreesConfig config, FellingTreesUserData userData, BigInteger gold, int way) {
        userData.setGold(userData.getGold().add(gold));

        // 日志
        AutoLogMgr.add(new LogFellingTreesItem(
                config.getActivityInfo().getActivityId(),
                getUserId(),
                config.getGoldItemId(),
                gold.toString(),
                userData.getGold().toString(),
                way
        ));
    }

    private boolean removeGold(FellingTreesConfig config, FellingTreesUserData userData, BigInteger gold, int way) {
        if (userData.getGold().compareTo(gold) < 0) {
            return false;
        }
        userData.setGold(userData.getGold().subtract(gold));

        // 日志
        AutoLogMgr.add(new LogFellingTreesItem(
                config.getActivityInfo().getActivityId(),
                getUserId(),
                config.getGoldItemId(),
                gold.multiply(BigInteger.valueOf(-1)).toString(),
                userData.getGold().toString(),
                way
        ));

        return true;
    }

    private void addNormalEquip(FellingTreesConfig config, FellingTreesUserData userData, List<FellingTreesEquip> equipList, int way) {
        Map<Integer, FellingTreesWeaponsConfig> weaponsConfigMap = config.getWeaponsConfigMap();
        for (FellingTreesEquip equip : equipList) {

            // 容错，再判断一下是否已有装备，避免炸
            FellingTreesWeaponsConfig weaponsConfig = weaponsConfigMap.get(equip.getEquipId());
            if (FellingTreesMgr.onlyOneEquip(equip.getEquipId()) && hasThisEquip(userData.getEquipMap(), equip.getEquipId())) {
                if (weaponsConfig.getType() == eFellingTreesEquipType.SpecialEquip.getValue()) {
                    // 灵宝 && 已拥有 => 【转化材料】
                    addItem(config, userData, PropertyHelper.parseStringToProperty(equip.getEquipId() + "=1"), way);
                }
                continue;
            }

            // 【正常加装备】
            if (equip.getUid() == -1) {
                equip.setUid(getNextUid(userData)); // 没UID就设置UID
            }
            userData.getEquipMap().put(equip.getUid(), equip);

            // 日志
            AutoLogMgr.add(new LogFellingTreesEquip(
                    config.getActivityInfo().getActivityId(),
                    getUserId(),
                    LogFellingTreesEquip.TYPE_GET,
                    equip,
                    way,
                    weaponsConfig.getType()
            ));
        }
    }

    /**
     * 添加灵宝
     * 返回转换了多少个灵宝
     */
    private SpecialEquipAddResultHelper addSpecialEquip(FellingTreesConfig config, FellingTreesUserData userData, Property property, int way) {
        List<FellingTreesEquip> asEquipList = new ArrayList<>();
        Property asItem = new Property();
        Property needTranItem = new Property();
        long totalTranCount = 0;
        long daoqiClearItemCount = 0;
        for (Map.Entry<Integer, BigInteger> entry : property.getGoods().entrySet()) {
            int equipId = entry.getKey();
            long count = entry.getValue().longValue();
            if (count <= 0) {
                continue;
            }
            // 记录下掉落的数量
            long originCount = count;
            // 以装备形式添加
            if (!hasThisEquip(userData.getEquipMap(), equipId)) {
                asEquipList.add(FellingTreesEquip.createSpecialEquip(equipId));
                count--;
            }
            // 以材料形式添加
            if (count > 0) {
                asItem.addProperty(equipId, BigInteger.valueOf(count));
                // 当前材料数量
                long curCount = userData.getItems().getCountByGoodsId(equipId).longValue();
                // 升至满级所需的数量
                long maxLevelCount = FellingTreesMgr.upgradeSpecialEquipMaxLevelCount(userData, equipId);
                // 超出的数量
                long moreCount = Math.max(0, curCount + count - maxLevelCount);
                if (moreCount > 0) {
                    // 超出的数量转为月灵石
                    FellingTreesWeaponsConfig weaponsConfig = config.getWeaponsConfigMap().get(equipId);
                    long tranCount = Long.parseLong(weaponsConfig.getParam());
                    // 月灵石
                    daoqiClearItemCount += tranCount * moreCount;
                    // 移除超出的
                    needTranItem.addProperty(equipId, BigInteger.valueOf(moreCount));
                    totalTranCount += moreCount;
                    log.info("玩家id:{},获得{}灵珠{}个,超出{}个,转换为{}个月灵石", player.getUserId(), equipId, originCount, moreCount, tranCount * moreCount);
                    entry.setValue(BigInteger.valueOf(Math.max(0, count - moreCount)));
                }
            }
        }
        // 添加
        addNormalEquip(config, userData, asEquipList, way); // 必须先加装备
        // 获得的灵宝
        addItem(config, userData, asItem, way);
        // 移除超出的灵宝
        removeItem(config, userData, needTranItem, way);

        SpecialEquipAddResultHelper resultHelper = new SpecialEquipAddResultHelper();
        resultHelper.setTotalTranCount(totalTranCount);
        resultHelper.setDaoqiClearItemCount(daoqiClearItemCount);
        return resultHelper;
    }

    /**
     * 添加道器
     */
    private void addDaoQi(FellingTreesConfig config, FellingTreesUserData userData, Property property, int way) {
        List<FellingTreesEquip> asEquipList = new ArrayList<>();
        for (Map.Entry<Integer, BigInteger> entry : property.getGoods().entrySet()) {
            int equipId = entry.getKey();
            // 最多只能获得一个
            long count = Math.min(1, entry.getValue().longValue());
            if (count <= 0) {
                continue;
            }

            // 以装备形式添加
            if (!hasThisEquip(userData.getEquipMap(), equipId)) {
                FellingTreesEquip equip = FellingTreesEquip.createSpecialEquip(equipId);
                // 增加道器词条
                addDaoQiParam(equip);
                asEquipList.add(equip);
            }
        }
        // 添加
        addNormalEquip(config, userData, asEquipList, way); // 必须先加装备
    }

    /**
     * 添加道器词条
     *
     * @param equip 装备
     */
    private void addDaoQiParam(FellingTreesEquip equip) {
        FellingTreesConfig config = FellingTreesMgr.getFellingTreesConfig();
        // 获取当前道器的词条
        List<FellingTreesEquipParam> paramList = equip.getParamList();
        // 初始化词条
        FellingTreesWeaponsConfig weaponsConfig = config.getWeaponsConfigMap().get(equip.getEquipId());
        String[] params = weaponsConfig.getParam().split("\\|");
        if (params.length <= paramList.size()) {
            // 词条满了或者配置没了
            return;
        }
        String param = params[paramList.size()];
        String[] split = param.split(";");
        addEquipParam(equip, eFellingTreesEquipParamType.DaoQi.getValue(), Integer.parseInt(split[0]));
    }

    /**
     * 增加一条词条
     *
     * @param equip      装备
     * @param paramType  词条属性类型
     * @param paramValue 词条属性值
     */
    private void addEquipParam(FellingTreesEquip equip, int paramType, int paramValue) {
        FellingTreesEquipParam equipParam = new FellingTreesEquipParam();
        equipParam.setType(paramType);
        equipParam.setValue(paramValue);
        equip.getParamList().add(equipParam);
    }

    /**
     * 更新道器词条
     */
    private void updateDaoQiParam(FellingTreesEquip equip, int paramValue, int maxValue) {
        List<FellingTreesEquipParam> paramList = equip.getParamList();
        if (paramList.size() == 0) {
            return;
        }
        updateEquipParam(equip, paramList.size() - 1, eFellingTreesEquipParamType.DaoQi.getValue(), paramValue, maxValue);
        // 判断词条是否满了
        if (equip.getParamList().get(paramList.size() - 1).getValue() >= maxValue) {
            // 解锁下一个词条
            addDaoQiParam(equip);
        }
    }

    private void daoQiParamAddOffset(FellingTreesEquip equip, int offsetValue, int maxValue) {
        List<FellingTreesEquipParam> paramList = equip.getParamList();
        if (paramList.size() == 0) {
            return;
        }
        equipParamAddOffset(equip, paramList.size() - 1, offsetValue, maxValue);
        // 判断词条是否满了
        if (equip.getParamList().get(paramList.size() - 1).getValue() >= maxValue) {
            // 解锁下一个词条
            addDaoQiParam(equip);
        }
    }

    /**
     * 更新词条
     */
    private void updateEquipParam(FellingTreesEquip equip, int paramIndex, int paramType, int paramValue, int maxValue) {
        if (paramIndex >= equip.getParamList().size()) {
            return;
        }
        FellingTreesEquipParam equipParam = equip.getParamList().get(paramIndex);
        equipParam.setType(paramType);
        equipParam.setValue(Math.min(paramValue, maxValue));
    }

    /**
     * 更新词条(增量)
     */
    private void equipParamAddOffset(FellingTreesEquip equip, int paramIndex, int offsetValue, int maxValue) {
        if (paramIndex >= equip.getParamList().size()) {
            return;
        }
        FellingTreesEquipParam equipParam = equip.getParamList().get(paramIndex);
        equipParam.setValue(Math.min(equipParam.getValue() + offsetValue, maxValue));
    }




}
